/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.app.dto.ShopHeadInfoDto;
import com.yami.shop.bean.event.ShopEmployeeSuperAdminEvent;
import com.yami.shop.bean.event.UpdateShopSuperAdminAccountEvent;
import com.yami.shop.bean.param.ShopDetailParam;
import com.yami.shop.bean.enums.AuditStatus;
import com.yami.shop.bean.enums.OfflineHandleEventStatus;
import com.yami.shop.bean.enums.OfflineHandleEventType;
import com.yami.shop.bean.enums.ShopStatus;
import com.yami.shop.bean.event.OpenShopInitEvent;
import com.yami.shop.bean.model.OfflineHandleEvent;
import com.yami.shop.bean.model.ShopAuditing;
import com.yami.shop.bean.model.ShopDetail;
import com.yami.shop.bean.model.ShopWallet;
import com.yami.shop.bean.param.OfflineHandleEventAuditParam;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.dao.ProductMapper;
import com.yami.shop.dao.ShopDetailMapper;
import com.yami.shop.dao.ShopWalletMapper;
import com.yami.shop.service.OfflineHandleEventService;
import com.yami.shop.service.ShopAuditingService;
import com.yami.shop.service.ShopDetailService;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author lgh on 2018/08/29.
 */
@Service
@AllArgsConstructor
public class ShopDetailServiceImpl extends ServiceImpl<ShopDetailMapper, ShopDetail> implements ShopDetailService {

    private final ShopDetailMapper shopDetailMapper;

    private final ShopAuditingService shopAuditingService;

    private final MapperFacade mapperFacade;

    private final ShopWalletMapper shopWalletMapper;

    private final OfflineHandleEventService offlineHandleEventService;

    private final ProductMapper productMapper;

    private final ApplicationContext applicationContext;

    private final PasswordEncoder passwordEncoder;


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "shop_detail", key = "#shopDetail.shopId")
    public void updateShopDetail(ShopDetail shopDetail, ShopDetail dbShopDetail) {
        // 使用saveOrUpdate可以只更新部分字段
        saveOrUpdate(shopDetail);
    }

    @Override
    public double getDistance(Double lat, Double lng, Long shopId) {
        return shopDetailMapper.getDistance(lat,lng,shopId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "shop_detail", key = "#shopId")
    public void deleteShopDetailByShopId(Long shopId) {
        // 先删除数据库中的信息，再删除图片
        shopDetailMapper.deleteById(shopId);
    }

    @Override
    @Cacheable(cacheNames = "shop_detail", key = "#shopId")
    public ShopDetail getShopDetailByShopId(Long shopId) {
        return shopDetailMapper.selectShopDetailById(shopId);
    }

    @Override
    @CacheEvict(cacheNames = "shop_detail", key = "#shopId")
    public void removeShopDetailCacheByShopId(Long shopId) {
    }

    @Override
    public ShopDetail getShopByMobile(String mobile) {
        return shopDetailMapper.getShopByMobile(mobile);
    }

    @Override
    public void updatePasswordByUserName(String username, String newPassword) {
        shopDetailMapper.updatePasswordByUserName(username, newPassword);
    }

    @Override
    public ShopDetail getShopDetailByUserId(String userId) {
        return shopDetailMapper.getShopDetailByUserId(userId);
    }

    /**
     * 申请开店
     *
     * @param userId
     * @param shopDetailParam
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyShop(String userId, ShopDetailParam shopDetailParam) {

        ShopDetail shopDetail = getShopDetailByUserId(userId);
        if (shopDetail != null && !Objects.equals(shopDetail.getShopStatus(), ShopStatus.NOTOPEN.value())) {
            // 您已经申请开启店铺,不能重新申请
            throw new YamiShopBindException("yami.cannot.reapply");
        }
        ShopDetail dbShopnameShop = shopDetailMapper.selectOne(new LambdaQueryWrapper<ShopDetail>().eq(ShopDetail::getShopName, shopDetailParam.getShopName()).ne(ShopDetail::getUserId, userId));
        if (dbShopnameShop != null) {
            // 店铺名称已存在
            throw new YamiShopBindException("yami.store.name.exist");
        }
        ShopDetail newShopDetail = mapperFacade.map(shopDetailParam, ShopDetail.class);

        Date now = new Date();
        // 如果是第一次申请开店
        if (shopDetail == null) {
            newShopDetail.setUserId(userId);
            newShopDetail.setCreateTime(now);
            newShopDetail.setShopOwner(userId);
            newShopDetail.setShopStatus(ShopStatus.NOTOPEN.value());
            newShopDetail.setIsDistribution(1);
        } else {
            newShopDetail.setShopId(shopDetail.getShopId());
            newShopDetail.setCreateTime(now);
        }


        newShopDetail.setUpdateTime(now);
        // 保存或更新
        saveOrUpdate(newShopDetail);
        //清除缓存
        removeShopDetailCacheByShopId(newShopDetail.getShopId());

        // 插入一条审核记录
        ShopAuditing auditing = shopAuditingService.getShopAuditingByUserId(userId);
        if (auditing == null) {
            auditing = new ShopAuditing();
            auditing.setShopId(newShopDetail.getShopId());
            auditing.setUserId(userId);
            auditing.setCreateTime(new Date());
        }
        auditing.setStatus(AuditStatus.WAITAUDIT.value());
        auditing.setUpdateTime(new Date());
        shopAuditingService.saveOrUpdate(auditing);
        if (Objects.isNull(shopDetail)) {
            // 第一次申请开店,店铺员工表插入一个超级管理员
            applicationContext.publishEvent(new ShopEmployeeSuperAdminEvent(newShopDetail));
        }
    }

    /**
     * 审核商家信息
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean audit(ShopAuditing shopAuditing) {
        shopAuditingService.updateById(shopAuditing);
        if (!Objects.equals(shopAuditing.getStatus(), AuditStatus.SUCCESSAUDIT.value())) {
            return true;
        }

        //修改店铺状态
        ShopDetail shopDetail = getShopDetailByShopId(shopAuditing.getShopId());
        if (shopDetail == null) {
            // 店铺信息不存在
            throw new YamiShopBindException("yami.store.not.exist");
        }
        shopDetail.setShopStatus(ShopStatus.OPEN.value());
        updateById(shopDetail);

        // 添加店铺钱包
        ShopWallet shopWallet = new ShopWallet();
        shopWallet.setVersion(0L);
        shopWallet.setUnsettledAmount(0.0);
        shopWallet.setSettledAmount(0.0);
        shopWallet.setFreezeAmount(0.0);
        shopWallet.setTotalSettledAmount(0.0);
        shopWallet.setShopId(shopAuditing.getShopId());
        shopWallet.setUpdateTime(new Date());
        shopWalletMapper.insert(shopWallet);

        // 新店初始化事件
        applicationContext.publishEvent(new OpenShopInitEvent(shopDetail));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "shop_detail", key = "#shopDetail.shopId")
    public void offline(ShopDetail shopDetail, String offlineReason, Long sysUserId) {
        // 添加下线处理记录
        Date now = new Date();
        OfflineHandleEvent offlineHandleEvent = new OfflineHandleEvent();
        offlineHandleEvent.setHandleId(shopDetail.getShopId());
        offlineHandleEvent.setHandleType(OfflineHandleEventType.SHOP.getValue());
        offlineHandleEvent.setCreateTime(now);
        offlineHandleEvent.setOfflineReason(offlineReason);
        offlineHandleEvent.setHandlerId(sysUserId);
        offlineHandleEvent.setShopId(shopDetail.getShopId());
        offlineHandleEvent.setStatus(OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue());
        offlineHandleEvent.setUpdateTime(now);
        offlineHandleEventService.save(offlineHandleEvent);

        // 更新店铺状态为下线
        shopDetailMapper.updateStatus(shopDetail.getShopId(), ShopStatus.OFFLINE.value());

        // 将该店铺所有的商品下线状态
        productMapper.offlineProdByShopId(shopDetail.getShopId());

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "shop_detail", key = "#offlineHandleEventAuditParam.handleId")
    public void auditOfflineShop(OfflineHandleEventAuditParam offlineHandleEventAuditParam, Long sysUserId) {
        // 审核通过
        if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            // 更新店铺为营业中状态
            shopDetailMapper.updateStatus(offlineHandleEventAuditParam.getHandleId(), ShopStatus.OPEN.value());
        }
        // 审核不通过
        else if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.DISAGREE_BY_PLATFORM.getValue())) {
            shopDetailMapper.updateStatus(offlineHandleEventAuditParam.getHandleId(), ShopStatus.OFFLINE.value());
        }
        offlineHandleEventService.auditOfflineEvent(offlineHandleEventAuditParam, sysUserId);
        //状态改变后清理缓存
        removeShopDetailCacheByShopId(offlineHandleEventAuditParam.getHandleId());
    }

    @Override
    public List<ShopHeadInfoDto> listHotShopsHead() {
        return shopDetailMapper.listHotShopsHead();
    }

    @Override
    public Page<ShopHeadInfoDto> searchShops(PageParam<ShopHeadInfoDto> page, ShopHeadInfoDto shopHeadInfoDto) {
        return shopDetailMapper.searchShops(page,shopHeadInfoDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertDetail(ShopDetail shopDetail, int count) {
        Date date = new Date();
        shopDetail.setShopStatus(1);
        shopDetail.setIsDistribution(1);
        shopDetail.setCreateTime(date);
        shopDetail.setUpdateTime(date);
        shopDetail.setPassword(passwordEncoder.encode(shopDetail.getPassword()));
        if ((this.checkMobile(shopDetail.getMobile(),null) + count)>0){
            // 该账号已存在，请重新输入
            throw new YamiShopBindException("yami.store.account.exist");
        }
        int nameCount = count(new LambdaQueryWrapper<ShopDetail>().eq(ShopDetail::getShopName, shopDetail.getShopName())
                .eq(ShopDetail::getShopStatus,1).ne(ShopDetail::getShopId, shopDetail.getShopId()));
        if (nameCount > 0) {
            // 已有相同名称
            throw new YamiShopBindException("yami.shop.name.have.already");
        }
        shopDetailMapper.insert(shopDetail);
        //创建店铺钱包
        ShopWallet shopWallet = new ShopWallet();
        shopWallet.setShopId(shopDetail.getShopId());
        shopWallet.setUnsettledAmount(0.0);
        shopWallet.setSettledAmount(0.0);
        shopWallet.setFreezeAmount(0.0);
        shopWallet.setTotalSettledAmount(0.0);
        shopWallet.setVersion(0L);
        shopWallet.setUpdateTime(new Date());
        shopWalletMapper.insert(shopWallet);
        // 店铺员工表插入一个超级管理员
        applicationContext.publishEvent(new ShopEmployeeSuperAdminEvent(shopDetail));
    }

    @Override
    public int checkMobile(String mobile, Long shopId) {
        return  count(new LambdaQueryWrapper<ShopDetail>()
                .eq(ShopDetail::getMobile, mobile)
                .ne(Objects.nonNull(shopId), ShopDetail::getShopId, shopId)
        );
    }

    @Override
    @CacheEvict(cacheNames = "shop_detail", key = "#shopId")
    public void updatePasswordOrMobile(Long shopId, String password, String mobile, Integer count) {
        ShopDetail shopDetail = new ShopDetail();
        shopDetail.setShopId(shopId);
        shopDetail.setPassword(passwordEncoder.encode(password));
        if (Objects.nonNull(mobile)){
            if ((this.checkMobile(shopDetail.getMobile(),shopId) + count)>0){
                // 该账号已存在，请重新输入
                throw new YamiShopBindException("yami.store.account.exist");
            }
            shopDetail.setMobile(mobile);
        }
        shopDetailMapper.updateById(shopDetail);
        // 店铺员工表更新超级管理员账号密码
        applicationContext.publishEvent(new UpdateShopSuperAdminAccountEvent(shopDetail));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "shop_detail", key = "#shopId")
    public void auditApply(Long eventId, Long shopId, String reapplyReason) {
        // 更新活动为待审核状态
        shopDetailMapper.updateStatus(shopId, ShopStatus.OFFLINE_AUDIT.value());

        // 更新事件状态
        offlineHandleEventService.updateToApply(eventId, reapplyReason);
    }

}
